package gui;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import util.Driver;

public class Stackulator implements KeyListener {
	
	private boolean clearError;
	private JLabel errorLabel;
	private JTextField output;
	
	private void makeNumButton(JPanel panel, int num, GridBagLayout gridbag, GridBagConstraints c) {
		JButton numButton = new JButton();
		numButton.setText(Integer.toString(num));
		numButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				numPressed( Integer.parseInt(((JButton) e.getSource()).getText()) );
			}
		});
		gridbag.setConstraints(numButton, c);
		panel.add(numButton);
	}
	
	private void makeOpButton(JPanel panel, String op, GridBagLayout gridbag, GridBagConstraints c) {
		JButton numButton = new JButton();
		numButton.setText(op);
		numButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				opPressed(((JButton) e.getSource()).getText());
			}
		});
		gridbag.setConstraints(numButton, c);
		panel.add(numButton);
	}
	
	public Stackulator() {
		JFrame frame = new JFrame();
		JPanel panel = new JPanel();
		panel.setFocusable(true);
		frame.setContentPane(panel);
		
		panel.addKeyListener(this);
		
		GridBagLayout gridbag = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		panel.setLayout(gridbag);
		
		// First row
		c.fill = GridBagConstraints.BOTH;
		
		c.gridwidth = GridBagConstraints.REMAINDER;
		output = new JTextField();
		output.setEditable(false);
		gridbag.setConstraints(output, c);
		panel.add(output);
		
		c.gridwidth = GridBagConstraints.REMAINDER;
		errorLabel = new JLabel();
		gridbag.setConstraints(errorLabel, c);
		panel.add(errorLabel);
		
		c.weightx = 1.0;
        c.gridwidth = 2;
        makeOpButton(panel, "(", gridbag, c);
		c.gridwidth = GridBagConstraints.REMAINDER;
        makeOpButton(panel, ")", gridbag, c);
		
        c.weightx = 1.0;
        c.gridwidth = 1;
		makeNumButton(panel, 7, gridbag, c);
		makeNumButton(panel, 8, gridbag, c);
		makeNumButton(panel, 9, gridbag, c);
		c.gridwidth = GridBagConstraints.REMAINDER;
		makeOpButton(panel, "+", gridbag, c);
		
		c.gridwidth = 1;
		makeNumButton(panel, 4, gridbag, c);
		makeNumButton(panel, 5, gridbag, c);
		makeNumButton(panel, 6, gridbag, c);
		c.gridwidth = GridBagConstraints.REMAINDER;
		makeOpButton(panel, "-", gridbag, c);
		
		c.gridwidth = 1;
		makeNumButton(panel, 1, gridbag, c);
		makeNumButton(panel, 2, gridbag, c);
		makeNumButton(panel, 3, gridbag, c);
		c.gridwidth = GridBagConstraints.REMAINDER;
		makeOpButton(panel, "*", gridbag, c);
		
		c.weightx = 0.0;
		c.gridwidth = GridBagConstraints.RELATIVE;
		makeNumButton(panel, 0, gridbag, c);
		c.gridwidth = GridBagConstraints.REMAINDER;
		makeOpButton(panel, "/", gridbag, c);
		
		makeOpButton(panel, "enter", gridbag, c);
		makeOpButton(panel, "backspace", gridbag, c);
		
		
		frame.pack();
		frame.setTitle("Stackulator");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
	}
	
	private void numPressed(int num) {
		if (clearError) errorLabel.setText("");
		output.setText( output.getText() + Integer.toString(num) );
	}
	
	private void opPressed(String op) {
		if (clearError) errorLabel.setText("");
		if (op.equals("enter")) {
			try {
				output.setText(Driver.evaluate(output.getText()));
			} catch (Exception e) {
				errorLabel.setText("Invalid Expression!");
				clearError = true;
			}
		} else if (op.equals("backspace")) {
			String text = output.getText();
			output.setText(text.substring(0, text.length()-1));
		} else {
			output.setText( output.getText() + op );
		}
	}
	
	public static void main (String[] args) {
		new Stackulator();
	}

	@Override
	public void keyPressed(KeyEvent arg0) {
		switch (arg0.getKeyCode()) {
		case KeyEvent.VK_BACK_SPACE: 
		case KeyEvent.VK_DELETE: opPressed("backspace"); break;
		
		case KeyEvent.VK_LEFT_PARENTHESIS: opPressed("("); break;
		case KeyEvent.VK_RIGHT_PARENTHESIS: opPressed(")"); break;
		
		case KeyEvent.VK_ENTER: opPressed("enter"); break;
		}
		
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		switch (arg0.getKeyChar()) {
		case '0': numPressed(0); break;
		case '1': numPressed(1); break;
		case '2': numPressed(2); break;
		case '3': numPressed(3); break;
		case '4': numPressed(4); break;
		case '5': numPressed(5); break;
		case '6': numPressed(6); break;
		case '7': numPressed(7); break;
		case '8': numPressed(8); break;
		case '9': numPressed(9); break;
		case '+': opPressed("+"); break;
		case '-': opPressed("-"); break;
		case '*': opPressed("*"); break;
		case '/': opPressed("/"); break;
		case '%': opPressed("%"); break;
		case '=': opPressed("enter"); break;
		case '(': opPressed("("); break;
		case ')': opPressed(")"); break;
		}
	}

}
